import os
import re
import shutil

import click
from androtools.android_sdk.build_tools import AAPT2, Dump
from androtools.android_sdk.platform_tools import ADB
from rich.progress import track


def get_app_name(path: str):
    a2 = AAPT2()
    out = a2.dump(Dump.badging, [path])[0]

    pattern = re.compile(r" versionName='([^']+)' ")
    version = "0.0"
    for line in out.splitlines():
        if "versionName=" in line:
            for item in pattern.finditer(line):
                version = item.groups()[0]
                break
            break

    for line in out.splitlines():
        if "application-label-zh-CN:" in line:
            return line.split("'")[1] + "_V" + version

    for line in out.splitlines():
        if "application-label:" in line:
            return line.split("'")[1] + "_V" + version

    # application: label='Settings'
    for line in out.splitlines():
        if "application: label=" in line:
            return line.split("'")[1] + "_V" + version


class BackupMaster:
    def __init__(self, adb_path: str | None = None):
        self.is_ready = True
        self.adb = ADB(adb_path)
        devs = self.adb.get_devices()
        if len(devs) == 0:
            print("无法找到可以备份的设备。")
            self.is_ready = False

    def backup_app(self, path: str = "APPs"):
        """备份第三方应用"""
        if not self.is_ready:
            print("无法找到Android的设备，无法备份。")
            return

        if not os.path.exists(path):
            os.mkdir(path)

        # 获取第三方应用
        result, _ = self.adb.run_shell_cmd(["pm", "list", "packages", "-3"])
        lines = result.splitlines()

        size = len(lines)
        counter = 0
        for line in lines:
            counter += 1
            print(f"{counter}/{size}", end="\r")
            pkg = line[8:]
            cmd = ["pm", "path", pkg]
            output, _ = self.adb.run_shell_cmd(cmd)
            app_path = output[8:].strip()
            _cmd = ["pull", app_path, os.path.join(path, pkg + ".apk")]
            print(_cmd)
            output, _ = self.adb.run_cmd(_cmd)
            print(output)

        for root, _, files in os.walk(path):
            for file in track(files, description="重命名应用..."):
                if not file.endswith(".apk"):
                    continue

                old_path = os.path.join(root, file)
                app_name = get_app_name(old_path)
                if app_name is None:
                    continue

                shutil.move(old_path, os.path.join(root, app_name + ".apk"))

    def restore_app(self, path: str = "Apps"):
        for root, _, files in os.walk(path):
            for file in track(files, description="安装应用..."):
                if not file.endswith(".apk"):
                    continue

                apk_path = os.path.join(root, file)
                self.adb.run_cmd(["install", apk_path])

        pass

    def backup_sdcard(self, path: str = "SDcard"):
        """备份SD卡中的数据，包含字体、照片、图片。"""
        if not self.is_ready:
            print("无法找到可以备份的设备")
            return

        if not os.path.exists(path):
            os.mkdir(path)

        dirs = [
            "Fonts",
            "DCIM",
            "Pictures",
        ]

        for item in dirs:
            print(f" - backup {item}")
            apath = os.path.join("sdcard", item)
            self.adb.run_cmd(["pull", apath, path])


@click.command()
@click.option("-p", "--path", default="Apps", help="应用目录")
def backup_app(path):
    """备份第三方应用"""
    backup_master = BackupMaster()
    backup_master.backup_app(path)


@click.command()
@click.option("-p", "--path", default="SDcard", help="应用目录")
def backup_sdcard(path):
    """备份SD卡中的数据，包含字体、照片、图片。"""
    bakup_master = BackupMaster()
    bakup_master.backup_sdcard(path)


@click.command()
@click.option(
    "-p", "--path", default="Apps", help="应用目录", type=click.Path(exists=True)
)
def restore_app(path):
    """恢复应用"""
    bm = BackupMaster()
    bm.restore_app(path)


@click.group()
def main():
    pass


main.add_command(backup_app)
main.add_command(restore_app)
main.add_command(backup_sdcard)
